/****************************************************************************
 *  _____       ______  _____
 * |_   _|     |  ____|/ ____|
 *   | |  _ __ | |__  | (___    Institute of Embedded Systems
 *   | | | '_ \|  __|  \___ \   Zürcher Hochschule für Angewandte
 *  _| |_| | | | |____ ____) |  Wissenschaften
 * |_____|_| |_|______|_____/   8401 Winterthur, Switzerland
 *
 ****************************************************************************
 *
 * @version $Rev: 181 $
 * @author  $Author: bacr $
 * @date    $Date: 2013-11-18 15:10:50 +0100 (lun., 18 nov. 2013) $
 *
 ***************************************************************************/

#ifndef __PTP2_LUT_H__
#define __PTP2_LUT_H__

/* copy */
#ifndef __PTP_NODE_TABLE_DEFINES__
#define __PTP_NODE_TABLE_DEFINES__

typedef struct ptp2_lut_t                   ptp2_lut_t;
typedef struct ptp2_lut_entry_t             ptp2_lut_entry_t;

typedef struct ptp2_slave_t                 ptp2_slave_t;
typedef enum   ptp2_slave_step_t            ptp2_slave_step_t;

typedef struct ptp2_node_address_t          ptp2_node_address_t;

#endif

#include <stdint.h>
#include <stdbool.h>

#include "hcpp/ptp2_types.h"
#include "hcpp/ptp2_datasets.h"
#include "packet/net_address.h"

#define PTP2_LUT_ENTRY_RAW_LEN              4
#define PTP2_LUT_ENTRY_MAC_FILLER_LEN       (PTP2_LUT_ENTRY_RAW_LEN * sizeof(uint32_t)) - MAC_ADDRESS_LEN
#define PTP2_LUT_ENTRY_IPV4_FILLER_LEN      (PTP2_LUT_ENTRY_RAW_LEN * sizeof(uint32_t)) - IPV4_ADDRESS_LEN
#define PTP2_LUT_ENTRY_IPV6_FILLER_LEN      (PTP2_LUT_ENTRY_RAW_LEN * sizeof(uint32_t)) - IPV6_ADDRESS_LEN

/**
 * A single LUT entry in software. Only the raw part is written down to the hardware.
 */
struct ptp2_lut_entry_t {
    ptp2_address_type_t         type;                                               /**< to distinguish between the address-types (duplicate). */
    bool                        active;                                             /**< true if LUT entry is written down to the hardware */
    ptp2_slave_t               *slave;                                              /**< points to a slave entry or to NULL (= initial value) */
    ptp2_node_address_t        *address;                                            /**< points to a address entry or to NULL (= initial value) */
    ptp2_foreign_master_ds_t   *fm_ds;                                              /**< points to a foreign master ds entry or to NULL (= initial value) */

    /** 4 x 4 bytes = 16 bytes of a single lut entry */
    union {
        uint32_t                raw[PTP2_LUT_ENTRY_RAW_LEN];                        /**< raw lut entry */
        struct {
            uint8_t             mac_filler[PTP2_LUT_ENTRY_MAC_FILLER_LEN];          /**< right-align address */
            mac_address_t       mac;                                                /**< lut entry used for a mac address */
        };
        struct {
            uint8_t             ipv4_filler[PTP2_LUT_ENTRY_IPV4_FILLER_LEN];        /**< right-align address */
            ipv4_address_t      ipv4;                                               /**< lut entry used for an IPv4 address */
        };
        struct {
            uint8_t             ipv6_filler[PTP2_LUT_ENTRY_IPV6_FILLER_LEN];        /**< right-align address */
            ipv6_address_t      ipv6;                                               /**< lut entry used for an IPv6 address */
        };
    };
};

int8_t  ptp2_lut_entry_cmp(ptp2_lut_entry_t *lut_entry_a, ptp2_lut_entry_t *lut_entry_b);

static inline void
ptp2_lut_clear_address(ptp2_lut_entry_t *lut_entry) {
    lut_entry->slave   = NULL;
    lut_entry->address = NULL;
    lut_entry->fm_ds   = NULL;

    for (uint8_t idx = 0; idx < PTP2_LUT_ENTRY_RAW_LEN; idx++) {
        lut_entry->raw[idx] = 0;
    }
}

#endif

